package view;

import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.lang.reflect.InvocationTargetException;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import weka.core.Instances;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.Remove;
import weka.gui.AttributeListPanel;
import weka.gui.AttributeSelectionPanel;
import weka.gui.InstancesSummaryPanel;
import controller.RelationshipController;

public class RelationshipminingView extends JFrame {
	private static final long serialVersionUID = 1L;
	private static final String START_BUTTON = "Start";
	private static final String EXIT_BUTTON = "Exit";
	private static final String GETDATA_BUTTON = "Get Data";
	private static final String OPEN_BUTTON = "Open";
	private static final String CLASSIFY_MODEL = "Classify Model";
	private static final String ATTRIBUTE_SELECTION = "AttributeSelection";
	private static final String RANDOMIZE = "Randomize";
	private static final String RESAMPLEWITHOUTREPLACEMENT = "Resample";

	InstancesSummaryPanel insSumPanel = new InstancesSummaryPanel();
	AttributeListPanel attListPanel;
	/** Panel to let the user toggle attributes */
	private AttributeSelectionPanel m_AttPanel = new AttributeSelectionPanel();
	private RelationshipController controller;
	private JLabel classifyMethodLabel;
	private JButton getDataButton, startButton, exitButton, m_OpenButton;
	/** Button for removing/reloading attributes */
	private JButton m_RemoveButton = new JButton("Remove");
	private JButton m_ReloadButton = new JButton("Reload");
	private JComboBox classifyMethodComboxBox;
	private JCheckBox attributeSelectionCheckBox, randomizeCheckBox,
			resampleWithoutReplacementCheckbox;
	private JSpinner kernelSpinner;
	JMenuItem attSelectItem;
	private JMenuBar jMenuBar = new JMenuBar();
	/** The working instances */
	private Instances m_Instances;

	public RelationshipminingView() {
		createGui();
	}

	public void createGui() {
		// Set app icon
		java.net.URL iconURL = getClass().getResource("/icon.png");
		// iconURL is null when not found
		javax.swing.ImageIcon icon = new javax.swing.ImageIcon(iconURL);
		this.setIconImage(icon.getImage());
		setSize(400, 600);
		getDataButton = new JButton(GETDATA_BUTTON);
		startButton = new JButton(START_BUTTON);
		exitButton = new JButton(EXIT_BUTTON);
		m_OpenButton = new JButton(OPEN_BUTTON);
		m_RemoveButton = new JButton("Remove");
		JMenu jToolMenu = new JMenu("Tool");
		attSelectItem = new JMenuItem("AttributeSelection");
		jToolMenu.add(attSelectItem);

		jMenuBar.add(jToolMenu);
		attributeSelectionCheckBox = new JCheckBox(ATTRIBUTE_SELECTION, false);
		randomizeCheckBox = new JCheckBox(RANDOMIZE, false);
		resampleWithoutReplacementCheckbox = new JCheckBox(
				RESAMPLEWITHOUTREPLACEMENT, false);
		String labels[] = { "SMO", "Naive Bayes", "C4.5" };
		classifyMethodComboxBox = new JComboBox<>(labels);
		// classifyMethodComboxBox.setPreferredSize(new Dimension(50, 10));
		classifyMethodLabel = new JLabel(CLASSIFY_MODEL);
		JPanel classifyPanel = new JPanel();
		classifyPanel.setLayout(new FlowLayout());
		JPanel filterPanel = new JPanel();
		// filterPanel.setLayout();
		filterPanel.setBorder(BorderFactory
				.createTitledBorder("Filter options"));
		filterPanel.setLayout(new BorderLayout());
		filterPanel.add(attributeSelectionCheckBox, BorderLayout.NORTH);
//		filterPanel
//				.add(resampleWithoutReplacementCheckbox, BorderLayout.CENTER);
		filterPanel.add(randomizeCheckBox, BorderLayout.SOUTH);
		JPanel upperMethodPanel = new JPanel();
		upperMethodPanel.setLayout(new BorderLayout());
		upperMethodPanel.setBorder(BorderFactory
				.createTitledBorder("Classification Chooser"));
		JPanel methodPanel = new JPanel();
		methodPanel.setLayout(new FlowLayout());

		methodPanel.add(classifyMethodLabel);
		methodPanel.add(classifyMethodComboxBox);

		final JPanel kernelPanel = new JPanel();
		kernelPanel.setLayout(new FlowLayout());
		classifyMethodComboxBox.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent arg0) {
				if (arg0.getItem() == "SMO") {
					kernelPanel.setVisible(true);
				} else {
					kernelPanel.setVisible(false);
				}
			}
		});

		SpinnerModel model = new SpinnerNumberModel(1.0, // initial
				0.0, // min
				3.0, // max
				0.1);
		kernelSpinner = new JSpinner(model);
		kernelSpinner.setPreferredSize(new Dimension(50, 20));
		kernelPanel.add(new JLabel("Kernel Exponent "));
		kernelPanel.add(kernelSpinner);

		upperMethodPanel.add(methodPanel, BorderLayout.NORTH);
		upperMethodPanel.add(kernelPanel, BorderLayout.SOUTH);

		classifyPanel.add(upperMethodPanel);
		classifyPanel.add(filterPanel);

		JPanel controlPanel = new JPanel();
		controlPanel.add(getDataButton);
		controlPanel.add(m_OpenButton);

		controlPanel.add(startButton);
		controlPanel.add(exitButton);
		// controlPanel.add(m_OutputButton);
		// Implement weka gui
		// Instances Summary Panel

		insSumPanel.setBorder(BorderFactory
				.createTitledBorder("Current relation"));
		// Attribute Selection Panel
		m_AttPanel.getSelectionModel().addListSelectionListener(
				new ListSelectionListener() {
					public void valueChanged(ListSelectionEvent e) {
						if (!e.getValueIsAdjusting()) {
							ListSelectionModel lm = (ListSelectionModel) e
									.getSource();

							for (int i = e.getFirstIndex(); i <= e
									.getLastIndex(); i++) {
								if (lm.isSelectedIndex(i)) {
									// m_AttSummaryPanel.setAttribute(i);
									// m_AttVisualizePanel.setAttribute(i);
									break;
								}
							}
						}
					}
				});
		JPanel attStuffHolderPanel = new JPanel();
		attStuffHolderPanel.setBorder(BorderFactory
				.createTitledBorder("Attributes"));
		attStuffHolderPanel.setLayout(new BorderLayout());
		attStuffHolderPanel.add(m_AttPanel, BorderLayout.CENTER);
		m_ReloadButton.setToolTipText("Reload Orginal Instances");
		m_ReloadButton.setEnabled(false);
		m_RemoveButton.setEnabled(false);
		m_RemoveButton.setToolTipText("Remove selected attributes.");
		m_RemoveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					Remove r = new Remove();
					int[] selected = m_AttPanel.getSelectedAttributes();
					if (selected.length == 0) {
						return;
					}
					if (selected.length == m_Instances.numAttributes()) {
						// Pop up an error optionpane
						JOptionPane.showMessageDialog(null,
								"Can't remove all attributes from data!\n",
								"Remove Attributes", JOptionPane.ERROR_MESSAGE);

						return;
					}
					r.setAttributeIndicesArray(selected);
					applyFilter(r);
					m_RemoveButton.setEnabled(false);
				} catch (Exception ex) {

					// Pop up an error optionpane
					JOptionPane.showMessageDialog(null,
							"Problem filtering instances:\n" + ex.getMessage(),
							"Remove Attributes", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		JPanel p1 = new JPanel();
		p1.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
		p1.setLayout(new FlowLayout());
		p1.add(m_RemoveButton);
		p1.add(m_ReloadButton);
		attStuffHolderPanel.add(p1, BorderLayout.SOUTH);
		attStuffHolderPanel.setPreferredSize(new Dimension(380, 350));
		JPanel leftPanel = new JPanel();
		leftPanel.setLayout(new BorderLayout());
		leftPanel.add(insSumPanel, BorderLayout.NORTH);
		leftPanel.add(attStuffHolderPanel, BorderLayout.SOUTH);
		leftPanel.setPreferredSize(new Dimension(380, 400));

		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BorderLayout());

		JPanel centerPanel = new JPanel();
		centerPanel.setLayout(new BorderLayout());
		centerPanel.add(classifyPanel, BorderLayout.NORTH);
		centerPanel.add(leftPanel, BorderLayout.SOUTH);
		mainPanel.add(centerPanel, BorderLayout.CENTER);
		mainPanel.add(controlPanel, BorderLayout.SOUTH);

		// Set positon
		mainPanel.add(jMenuBar, BorderLayout.NORTH);
		Toolkit tk = Toolkit.getDefaultToolkit();
		Dimension screenSize = tk.getScreenSize();
		final int WIDTH = screenSize.width;
		final int HEIGHT = screenSize.height;
		// Setup the frame accordingly
		// This is assuming you are extending the JFrame //class
		this.setResizable(false);
		this.setLocation((WIDTH - this.getWidth()) / 2,
				(HEIGHT - this.getHeight()) / 2);

		// ... finalize layout
		this.setContentPane(mainPanel);
		this.pack();

		this.setTitle("RelationshipMining Tools");
		// The window closing event should probably be passed to the
		// Controller in a real program, but this is a short example.
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	public Instances getM_Instances() {
		return m_Instances;
	}

	public void setM_Instances(Instances m_Instances) {
		this.m_Instances = m_Instances;
	}

	// Lắng nghe sự kiện view
	public void addExitButonListener(ActionListener ac) {
		exitButton.addActionListener(ac);
	}

	public void addGetDataButonListener(ActionListener ac) {
		getDataButton.addActionListener(ac);
	}

	public void addStartFButonListener(ActionListener ac) {
		startButton.addActionListener(ac);
	}

	public void addOpenButonListener(ActionListener ac) {
		m_OpenButton.addActionListener(ac);
	}

	public void addReloadButonListener(ActionListener ac) {
		m_ReloadButton.addActionListener(ac);
	}

	// Get model
	public JComboBox getComboBox() {
		return this.classifyMethodComboxBox;
	}

	public boolean getAttributeSelectionCheckbox() {
		return this.attributeSelectionCheckBox.isSelected();
	}

	public boolean getRandomizeCheckbox() {
		return this.randomizeCheckBox.isSelected();
	}

	public boolean getResampleCheckbox() {
		return this.resampleWithoutReplacementCheckbox.isSelected();
	}

	// show message
	public void showMessage(String msg) {
		JOptionPane.showMessageDialog(this, msg);
	}

	public void setEnableGetDataButton(boolean value) {
		getDataButton.setEnabled(value);
	}

	public double getKernelExponent() {
		return (double) this.kernelSpinner.getValue();
	}

	public void setInstances(Instances ins) {
		m_ReloadButton.setEnabled(true);
		m_Instances = ins;
		Runnable r = new Runnable() {
			public void run() {
				boolean first = (m_AttPanel.getTableModel() == null);
				m_AttPanel.setInstances(m_Instances);
				insSumPanel.setInstances(m_Instances);
				// attListPanel.setInstances(m_Instances);
				if (first) {
					TableModel model = m_AttPanel.getTableModel();
					model.addTableModelListener(new TableModelListener() {
						public void tableChanged(TableModelEvent e) {
							if (m_AttPanel.getSelectedAttributes() != null
									&& m_AttPanel.getSelectedAttributes().length > 0) {
								m_RemoveButton.setEnabled(true);
							} else {
								m_RemoveButton.setEnabled(false);
							}
						}
					});
				}

				// select the first attribute in the list
				m_AttPanel.getSelectionModel().setSelectionInterval(0, 0);
				try {

					// int oldIndex = m_Instances.classIndex();

					m_Instances.setClassIndex(m_Instances.numAttributes() - 1);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		if (SwingUtilities.isEventDispatchThread()) {
			r.run();
		} else {
			try {
				SwingUtilities.invokeAndWait(r);
			} catch (InvocationTargetException | InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Passes the dataset through the filter that has been configured for use.
	 * 
	 * @param filter
	 *            the filter to apply
	 */
	public void applyFilter(final Filter filter) {

		Thread m_IOThread = null;
		if (m_IOThread == null) {
			m_IOThread = new Thread() {
				public void run() {
					try {

						if (filter != null) {
							Instances copy = new Instances(m_Instances);
							copy.setClassIndex(-1);
							filter.setInputFormat(copy);
							Instances newInstances = Filter.useFilter(copy,
									filter);
							if (newInstances == null
									|| newInstances.numAttributes() < 1) {
								throw new Exception("Dataset is empty.");
							}
							m_Instances = newInstances;
							setInstances(m_Instances);
						}

					} catch (Exception ex) {

						// Pop up an error optionpane
						JOptionPane.showMessageDialog(
								null,
								"Problem filtering instances:\n"
										+ ex.getMessage(), "Apply Filter",
								JOptionPane.ERROR_MESSAGE);

					}
				}
			};
			m_IOThread.start();
		} else {
			JOptionPane.showMessageDialog(this,
					"Can't apply filter at this time,\n"
							+ "currently busy with other IO", "Apply Filter",
					JOptionPane.WARNING_MESSAGE);
		}
	}

	public void addAttributeselectionListener(ActionListener ac) {
		this.attSelectItem.addActionListener(ac);
	}
}
